/*
 *  AShader.cpp
 *  Amano Engine
 *
 *  Created by Aurelien Serandour on 07/03/11.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */

#include <stdlib.h>
#include <stdio.h>

#include "../include/AShader.h"
#include "../include/loader.h"

using namespace Amano;

AShader::AShader( const char* filenameVS, const char* filenamePS )
{
	GLint vertexShader = readAndCompileShader( filenameVS, GL_VERTEX_SHADER );
	GLint pixelShader = readAndCompileShader( filenamePS, GL_FRAGMENT_SHADER );
	
	if (vertexShader && pixelShader)
	{
		m_shaderProgram = glCreateProgram();
		glAttachShader(m_shaderProgram, vertexShader);
		glAttachShader(m_shaderProgram, pixelShader);
		
		glLinkProgram(m_shaderProgram);
		
		// check if everything was correct
		GLint linkStatus;
		glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, &linkStatus);
		
		if (linkStatus != GL_TRUE)
		{
			GLint logsize;
			glGetProgramiv(m_shaderProgram, GL_INFO_LOG_LENGTH, &logsize);
			char* log = (char*)malloc(logsize+1);
			
			if(log == NULL)
			{
				fprintf(stderr, "failed allocating memory\n");
			}
			else
			{
				glGetProgramInfoLog(m_shaderProgram, logsize, &logsize, log);
				fprintf(stderr, "program link went wrong:\n%s", log);
				free(log);
			}
		}
		
		glDetachShader(m_shaderProgram, vertexShader);
		glDetachShader(m_shaderProgram, pixelShader);
		
		glDeleteShader(vertexShader);
		glDeleteShader(pixelShader);
	}
}

GLint AShader::readAndCompileShader( const char* filename, GLenum type )
{
	GLint shader = glCreateShader(type);
	if (shader = 0)
	{
		printf("cannot create shader %s\n", filename);
		return NULL;
	}
	
	const char* shaderSource = LoadShader(filename);
	
	if (shaderSource == NULL)
	{
		return NULL;
	}
	
	glShaderSource(shader, 1, &shaderSource, NULL);
	glCompileShader(shader);
	
	// check if compilation was successful
	GLint compileStatus;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
	
	if (compileStatus != GL_TRUE)
	{
		GLint logsize;
		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logsize);
		char* log = (char*)malloc(logsize+1);		
		if(log == NULL)
		{
			fprintf(stderr, "failed allocating memory\n");
		}
		else
		{
			glGetShaderInfoLog(shader, logsize, &logsize, log);
			fprintf(stderr, "shader compilation went wrong %s:\n%s", filename, log);
			free(log);
		}
		
		glDeleteShader(shader);
		return NULL;
	}
	
	free((char*)shaderSource);
	
	return shader;
}

AShader::~AShader()
{
	if (m_shaderProgram)
		glDeleteProgram(m_shaderProgram);
}

void AShader::addLocation( const char* name )
{
	GLint loc = glGetUniformLocation( m_shaderProgram, name );
	if ( loc != -1 )
	{
		m_locations[name] = loc;
	}
}

GLint AShader::getLocation( const char* name )
{
	AShaderLocationLibrary::iterator it = m_locations.find(name);
	
	if ( it == m_locations.end() )
	{
		return -1;
	}
	else
	{
		return it->second;
	}
}